import base64
import pickle

from django.shortcuts import render

# Create your views here.

# POST/cart/
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

from cart import constants
from cart.serializers import CartSerializer, CartSKUSerializer, CartDelSerializer
from goods.models import SKU


class CartView(APIView):
    def perform_authentication(self, request):
        """让当前视图跳过DRF框架认证过程"""
        pass

    # GET /cart/
    def get(self, request):
        """
        购物车记录获取
        1.获取用户的购物车记录
            1.1 如果已经登录那么将从redis中获取
            2.2 如果用户未登录将从cookie中获取记录
        2. 根据用户的购物车中商品的id获取对应的商品数据
        3. 将购物车数据序列化,并返回
        """
        # 1.获取用户的购物车记录
        # 获取用户信息
        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 1.1 如果已经登录那么将从redis中获取
            # 与redis数据库建立链接
            redis_conn = get_redis_connection('cart')

            # hash:获取存储时的key值
            cart_key = 'cart_%s' % user.id

            # 从redis中取出该用户存储的所有商品id和数量
            redis_cart = redis_conn.hgetall(cart_key)

            # set:获取该用户勾选的商品id
            cart_select_key = 'cart_select_%s' % user.id
            redis_cart_selected = redis_conn.smembers(cart_select_key)

            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in redis_cart_selected
                }
        else:
            # 2.2 如果用户未登录将从cookie中获取记录
            cookie_cart = request.COOKIES.get('cart')
            # 将记录进行解析
            if cookie_cart:
                cart_dict = pickle.loads(base64.b64decode(cookie_cart))
            else:
                cart_dict = {}

        # 3.将购物车数据序列化, 并返回
        skus = SKU.objects.filter(id__in=cart_dict.keys())
        for sku in skus:
            # 给sku商品增加属性count和selected,分别保存用户购物车中添加的该商品的数量和勾选状态
            sku.count = cart_dict[sku.id]['count']
            sku.selected = cart_dict[sku.id]['selected']

        # 3.将购物车数据序列化并返回
        serializer = CartSKUSerializer(skus, many=True)
        return Response(serializer.data)

    # POST /cart/
    def post(self, request):
        """购物车记录添加"""
        # 1.获取参数并进行校验(参数完整性,sku_id商品是否存在,count是否大于商品库存)
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 获取校验之后的数据
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']

        try:
            user = request.user  # 如果用户已经登录,就是用户,如果没有登录那就是匿名用户
        except Exception:
            user = None
        # 2.保存用户的购物车数据
        if user and user.is_authenticated:
            # 2.1 如果用户已经登录,在redis中保存购物车记录
            # 获取链接对象
            redis_conn = get_redis_connection('cart')

            # hash:保存用户购物车添加的商品id和对应数量count
            cart_key = 'cart_%s' % user.id

            # 如果redis购物车已经添加该商品,数量需要进行累加
            redis_conn.hincrby(cart_key, sku_id, count)

            # set:保存用户购物车中被勾选的商品id
            cart_selected_key = 'cart_select_%s' % user.id

            if selected:
                redis_conn.sadd(cart_selected_key, sku_id)

            return Response(serializer.validated_data, status=status.HTTP_201_CREATED)

        else:
            # 2.2如果未登录,那么在cookie中保存用户的购物车记录
            # 获取原始cookie购物车数量
            cookie_cart = request.COOKIES.get('cart')  # None

            if cookie_cart:
                """<sku_id>:{
                    'count':'<count>',
                    'selected':'<selected>'
                } 解析出来的东西
                """
                cart_dict = pickle.loads(base64.b64decode(cookie_cart))
            else:
                cart_dict = {}

            # 保存购物车数据
            if sku_id in cart_dict.keys():
                # 数量累加
                count += cart_dict[sku_id]['count']

            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }

            # 3. 返回应答,购物车记录添加成功
            response = Response(serializer.validated_data, status=status.HTTP_201_CREATED)
            # 设置cookie购物车数据
            cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()  # str
            response.set_cookie('cart', cart_data, max_age=constants.CART_COOKIE_EXPIRES)

            return response

    # PUT /cart/
    def put(self, request):
        """购物车记录修改"""
        # 1.获取参数并进行校验(参数的完整性,count是否大于商品库存)
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']

        # 获取用户
        try:
            user = request.user
        except Exception:
            user = None
        # 2. 判断用户是否登录
        if user and user.is_authenticated:
            # 2.1 登录的用户将修改的数据存入redis
            redis_conn = get_redis_connection('cart')

            # 更新redis hash中对应的商品数量
            cart_key = 'cart_%s' % user.id
            redis_conn.hset(cart_key, sku_id, count)
            # 跟新redis set中商品的勾选状态
            cart_select_key = 'cart_select_%s'% user.id
            if selected:
                redis_conn.sadd(cart_select_key, sku_id)
            else:
                redis_conn.srem(cart_select_key, sku_id)
            return Response(serializer.validated_data)
        else:
            # 2.2 未登录的用户将数据存入cookie
            response = Response(serializer.validated_data)
            # 获取cookie中的购物车数据
            cookie_cart = request.COOKIE.get('cart')  # None
            if cookie_cart is None:
                # 购物车无数据
                return response
            # 解析cookie中的购物车数据
            cart_dict = pickle.loads(base64.b64decode(cookie_cart))

            if not cart_dict:
                return response
            # 更新购物车数据
            cart_dict['sku_id']={
                'count': count,
                'selected': selected
            }

            # 返回应答,更新成功
            cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()
            response.set_cookie('cart', cart_data, max_age=constants.CART_COOKIE_EXPIRES)
            return response


    # DELETE /cart/
    def delete(self, request):
        """删除商品数据"""
        # 获取参数并进行校验(参数的完整性,查询商品数据库中是否有该商品
        serializer = CartDelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 获取校验之后的数据
        sku_id = serializer.validated_data['sku_id']

        # 判断用户是否登录
        try:
            user = request.user

        except Exception:
            user = None

        if user and user.is_authenticated:
            # 如果登录,那么就删除redis中的该商品数据
            redis_conn = get_redis_connection('cart')

            # 删除hash中指定的属性和值
            cart_key = 'cart_%s' % user.id
            redis_conn.hdel(cart_key, sku_id)

            # 从redis set删除勾选的状态
            cart_select_key = 'cart_select_%s' % user.id
            redis_conn.srem(cart_select_key, sku_id)

        else:
            # 如果未登录,那么就是删除cookie中的商品数据
            response = Response(status=status.HTTP_204_NO_CONTENT)

            cookie_cart = request.COOKIES.get('cart')

            if cookie_cart is None:
                return response

            cart_dict = pickle.loads(base64.b64decode(cookie_cart))

            if not cart_dict:
                return response

            # 删除购物车中对应的数据
            if sku_id in cart_dict:
                del cart_dict[sku_id]

                # 重新设置购物车cookie数据
                cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()
                response.set_cookie('cart', cart_data, max_age=constants.CART_COOKIE_EXPIRES)
            # 返回应答, 删除成功
            return response